package com.netkit;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.util.internal.ConcurrentHashMap;

public class SessionGroup {
	private final ConcurrentMap<Serializable, Session> sessionMap = new ConcurrentHashMap();

	private final ChannelFutureListener remover = new ChannelFutureListener() {
		public void operationComplete(ChannelFuture future) throws Exception {
			int sessionId = future.getChannel().getId().intValue();
			List keys = SessionGroup.this.findKeysBySessionId(sessionId);
			SessionGroup.this.remove(keys);
		}
	};

	public synchronized boolean add(Serializable key, Session s) {
		if ((s instanceof Session)) {
			Session session = s;
			Channel channel = session.getChannel();

			boolean added = this.sessionMap.putIfAbsent(key, s) == null;
			if (added) {
				channel.getCloseFuture().addListener(this.remover);
			}
			return added;
		}
		return false;
	}

	public synchronized void close() {
		for(Map.Entry<Serializable, Session> entry : sessionMap.entrySet()){
			Session s = entry.getValue();
			s.close();
		}
		sessionMap.clear();
	}


	public boolean isEmpty() {
		return this.sessionMap.isEmpty();
	}

	public synchronized int remove(Session session) {
		if (session == null) {
			return 0;
		}
		List keys = findKeysBySessionId(session.getSessionId());
		int count = remove(keys);
		return count;
	}

	public synchronized Session remove(Serializable key) {
		Session s = (Session) this.sessionMap.remove(key);
		if (s == null) {
			return null;
		}
		s.getChannel().getCloseFuture().removeListener(this.remover);
		return s;
	}

	public synchronized int remove(Collection<Serializable> keys) {
		int count = 0;
		for (Serializable key : keys) {
			Session s = remove(key);
			if (s != null) {
				count++;
			}
		}
		return count;
	}

	public Session get(Serializable key) {
		return (Session) this.sessionMap.get(key);
	}

	public List<Serializable> findKeysBySessionId(int sessionId) {
		List<Serializable> keys = new ArrayList<Serializable>();

		for (Entry<Serializable, Session> entry : sessionMap.entrySet()) {
			Session s = (Session) entry.getValue();
			if (s.getSessionId() == sessionId) {
				keys.add(entry.getKey());
			}
		}

		return keys;
	}

	public int size() {
		return this.sessionMap.size();
	}

	public Collection<Session> sessions() {
		return this.sessionMap.values();
	}

	public Collection<Serializable> keys() {
		return this.sessionMap.keySet();
	}
}